package com.smart.community.region.validator;

import com.smart.community.region.vo.TemplateValidationResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.regex.Pattern;

/**
 * 模板数据验证器
 * 
 * @author Wu.Liang
 * @since 2025-01-30
 */
@Slf4j
@Component
public class TemplateDataValidator {

    // 正则表达式
    private static final Pattern BUILDING_NO_PATTERN = Pattern.compile("^[A-Za-z0-9]{1,20}$");
    private static final Pattern HOUSEHOLD_CODE_PATTERN = Pattern.compile("^[A-Za-z0-9\\-]{1,50}$");
    private static final Pattern ROOM_NUMBER_PATTERN = Pattern.compile("^[0-9]{1,10}$");

    /**
     * 验证楼栋数据
     */
    public List<TemplateValidationResult.ValidationError> validateBuildingData(
            List<Map<String, Object>> buildingData, 
            Long communityId,
            Set<String> existingBuildingNos) {
        
        List<TemplateValidationResult.ValidationError> errors = new ArrayList<>();
        Set<String> buildingNos = new HashSet<>();
        
        for (int i = 0; i < buildingData.size(); i++) {
            Map<String, Object> building = buildingData.get(i);
            int rowNumber = i + 2; // Excel从第2行开始，第1行是表头
            
            // 验证楼栋编号
            String buildingNo = getStringValue(building, "buildingNo");
            if (!StringUtils.hasText(buildingNo)) {
                errors.add(createError("楼栋信息", rowNumber, "楼栋编号", "必填字段", "楼栋编号不能为空"));
                continue;
            }
            
            if (!BUILDING_NO_PATTERN.matcher(buildingNo).matches()) {
                errors.add(createError("楼栋信息", rowNumber, "楼栋编号", "格式错误", 
                    "楼栋编号只能包含字母和数字，长度1-20位"));
            }
            
            // 验证楼栋编号唯一性
            if (buildingNos.contains(buildingNo)) {
                errors.add(createError("楼栋信息", rowNumber, "楼栋编号", "重复错误", 
                    "楼栋编号在模板中重复：" + buildingNo));
            } else if (existingBuildingNos.contains(buildingNo)) {
                errors.add(createError("楼栋信息", rowNumber, "楼栋编号", "重复错误", 
                    "楼栋编号在社区中已存在：" + buildingNo));
            } else {
                buildingNos.add(buildingNo);
            }
            
            // 验证楼栋名称
            String buildingName = getStringValue(building, "buildingName");
            if (!StringUtils.hasText(buildingName)) {
                errors.add(createError("楼栋信息", rowNumber, "楼栋名称", "必填字段", "楼栋名称不能为空"));
            } else if (buildingName.length() > 50) {
                errors.add(createError("楼栋信息", rowNumber, "楼栋名称", "长度错误", "楼栋名称不能超过50个字符"));
            }
            
            // 验证楼层数
            Integer floorCount = getIntegerValue(building, "floorCount");
            if (floorCount == null) {
                errors.add(createError("楼栋信息", rowNumber, "楼层数", "必填字段", "楼层数不能为空"));
            } else if (floorCount < 1 || floorCount > 100) {
                errors.add(createError("楼栋信息", rowNumber, "楼层数", "范围错误", "楼层数必须在1-100之间"));
            }
            
            // 验证单元数量
            Integer unitCount = getIntegerValue(building, "unitCount");
            if (unitCount == null) {
                errors.add(createError("楼栋信息", rowNumber, "单元数量", "必填字段", "单元数量不能为空"));
            } else if (unitCount < 1 || unitCount > 20) {
                errors.add(createError("楼栋信息", rowNumber, "单元数量", "范围错误", "单元数量必须在1-20之间"));
            }
            
            // 验证每层户数
            Integer unitsPerFloor = getIntegerValue(building, "unitsPerFloor");
            if (unitsPerFloor == null) {
                errors.add(createError("楼栋信息", rowNumber, "每层户数", "必填字段", "每层户数不能为空"));
            } else if (unitsPerFloor < 1 || unitsPerFloor > 20) {
                errors.add(createError("楼栋信息", rowNumber, "每层户数", "范围错误", "每层户数必须在1-20之间"));
            }
        }
        
        return errors;
    }

    /**
     * 验证单元数据
     */
    public List<TemplateValidationResult.ValidationError> validateUnitData(
            List<Map<String, Object>> unitData,
            Long communityId,
            Map<String, Map<String, Object>> buildingMap,
            Map<String, Set<Integer>> buildingUnitMap) {
        
        List<TemplateValidationResult.ValidationError> errors = new ArrayList<>();
        
        for (int i = 0; i < unitData.size(); i++) {
            Map<String, Object> unit = unitData.get(i);
            int rowNumber = i + 2; // Excel从第2行开始，第1行是表头
            
            // 验证楼栋编号
            String buildingNo = getStringValue(unit, "buildingNo");
            if (!StringUtils.hasText(buildingNo)) {
                errors.add(createError("单元信息", rowNumber, "楼栋编号", "必填字段", "楼栋编号不能为空"));
                continue;
            }
            
            // 验证楼栋是否存在
            Map<String, Object> building = buildingMap.get(buildingNo);
            if (building == null) {
                errors.add(createError("单元信息", rowNumber, "楼栋编号", "关联错误", 
                    "楼栋编号不存在：" + buildingNo));
                continue;
            }
            
            // 验证单元编号
            Integer unitNo = getIntegerValue(unit, "unitNo");
            if (unitNo == null) {
                errors.add(createError("单元信息", rowNumber, "单元编号", "必填字段", "单元编号不能为空"));
            } else if (unitNo < 1 || unitNo > 99) {
                errors.add(createError("单元信息", rowNumber, "单元编号", "范围错误", "单元编号必须在1-99之间"));
            } else {
                // 验证单元编号唯一性
                Set<Integer> unitNos = buildingUnitMap.computeIfAbsent(buildingNo, k -> new HashSet<>());
                if (unitNos.contains(unitNo)) {
                    errors.add(createError("单元信息", rowNumber, "单元编号", "重复错误", 
                        "楼栋" + buildingNo + "中单元编号重复：" + unitNo));
                } else {
                    unitNos.add(unitNo);
                }
            }
            
            // 验证单元名称
            String unitName = getStringValue(unit, "unitName");
            if (!StringUtils.hasText(unitName)) {
                errors.add(createError("单元信息", rowNumber, "单元名称", "必填字段", "单元名称不能为空"));
            } else if (unitName.length() > 50) {
                errors.add(createError("单元信息", rowNumber, "单元名称", "长度错误", "单元名称不能超过50个字符"));
            }
            
            // 验证楼层数一致性
            Integer floorCount = getIntegerValue(unit, "floorCount");
            if (floorCount == null) {
                errors.add(createError("单元信息", rowNumber, "楼层数", "必填字段", "楼层数不能为空"));
            } else {
                Integer buildingFloorCount = getIntegerValue(building, "floorCount");
                if (buildingFloorCount != null && !floorCount.equals(buildingFloorCount)) {
                    errors.add(createError("单元信息", rowNumber, "楼层数", "一致性错误", 
                        "单元楼层数(" + floorCount + ")与楼栋楼层数(" + buildingFloorCount + ")不一致"));
                }
            }
            
            // 验证房间数量计算
            Integer roomCount = getIntegerValue(unit, "roomCount");
            if (roomCount == null) {
                errors.add(createError("单元信息", rowNumber, "房间数量", "必填字段", "房间数量不能为空"));
            } else {
                Integer buildingUnitsPerFloor = getIntegerValue(building, "unitsPerFloor");
                if (buildingUnitsPerFloor != null && floorCount != null) {
                    int expectedRoomCount = floorCount * buildingUnitsPerFloor;
                    if (roomCount != expectedRoomCount) {
                        errors.add(createError("单元信息", rowNumber, "房间数量", "计算错误", 
                            "房间数量(" + roomCount + ")应该等于楼层数(" + floorCount + ")×每层户数(" + buildingUnitsPerFloor + ")=" + expectedRoomCount));
                    }
                }
            }
        }
        
        return errors;
    }

    /**
     * 验证房户数据
     */
    public List<TemplateValidationResult.ValidationError> validateHouseholdData(
            List<Map<String, Object>> householdData,
            Long communityId,
            Map<String, Map<String, Object>> buildingMap,
            Map<String, Map<String, Object>> unitMap,
            Set<String> existingHouseholdCodes) {
        
        List<TemplateValidationResult.ValidationError> errors = new ArrayList<>();
        Set<String> householdCodes = new HashSet<>();
        
        for (int i = 0; i < householdData.size(); i++) {
            Map<String, Object> household = householdData.get(i);
            int rowNumber = i + 2; // Excel从第2行开始，第1行是表头
            
            // 验证楼栋编号
            String buildingNo = getStringValue(household, "buildingNo");
            if (!StringUtils.hasText(buildingNo)) {
                errors.add(createError("房户信息", rowNumber, "楼栋编号", "必填字段", "楼栋编号不能为空"));
                continue;
            }
            
            // 验证楼栋是否存在
            Map<String, Object> building = buildingMap.get(buildingNo);
            if (building == null) {
                errors.add(createError("房户信息", rowNumber, "楼栋编号", "关联错误", 
                    "楼栋编号不存在：" + buildingNo));
                continue;
            }
            
            // 验证单元编号
            Integer unitNo = getIntegerValue(household, "unitNo");
            if (unitNo == null) {
                errors.add(createError("房户信息", rowNumber, "单元编号", "必填字段", "单元编号不能为空"));
                continue;
            }
            
            // 验证单元是否存在
            String unitKey = buildingNo + "-" + unitNo;
            Map<String, Object> unit = unitMap.get(unitKey);
            if (unit == null) {
                errors.add(createError("房户信息", rowNumber, "单元编号", "关联错误", 
                    "单元编号不存在：楼栋" + buildingNo + "单元" + unitNo));
                continue;
            }
            
            // 验证房户编号
            String householdCode = getStringValue(household, "householdCode");
            if (!StringUtils.hasText(householdCode)) {
                errors.add(createError("房户信息", rowNumber, "房户编号", "必填字段", "房户编号不能为空"));
            } else if (!HOUSEHOLD_CODE_PATTERN.matcher(householdCode).matches()) {
                errors.add(createError("房户信息", rowNumber, "房户编号", "格式错误", 
                    "房户编号只能包含字母、数字和连字符，长度1-50位"));
            } else {
                // 验证房户编号唯一性
                if (householdCodes.contains(householdCode)) {
                    errors.add(createError("房户信息", rowNumber, "房户编号", "重复错误", 
                        "房户编号在模板中重复：" + householdCode));
                } else if (existingHouseholdCodes.contains(householdCode)) {
                    errors.add(createError("房户信息", rowNumber, "房户编号", "重复错误", 
                        "房户编号在社区中已存在：" + householdCode));
                } else {
                    householdCodes.add(householdCode);
                }
            }
            
            // 验证房间号
            String roomNumber = getStringValue(household, "roomNumber");
            if (!StringUtils.hasText(roomNumber)) {
                errors.add(createError("房户信息", rowNumber, "房间号", "必填字段", "房间号不能为空"));
            } else if (!ROOM_NUMBER_PATTERN.matcher(roomNumber).matches()) {
                errors.add(createError("房户信息", rowNumber, "房间号", "格式错误", "房间号只能包含数字，长度1-10位"));
            }
            
            // 验证楼层号
            Integer floorNumber = getIntegerValue(household, "floorNumber");
            if (floorNumber == null) {
                errors.add(createError("房户信息", rowNumber, "楼层号", "必填字段", "楼层号不能为空"));
            } else {
                Integer buildingFloorCount = getIntegerValue(building, "floorCount");
                if (buildingFloorCount != null && (floorNumber < 1 || floorNumber > buildingFloorCount)) {
                    errors.add(createError("房户信息", rowNumber, "楼层号", "范围错误", 
                        "楼层号必须在1-" + buildingFloorCount + "之间"));
                }
            }
            
            // 验证面积
            BigDecimal area = getBigDecimalValue(household, "area");
            if (area == null) {
                errors.add(createError("房户信息", rowNumber, "面积", "必填字段", "面积不能为空"));
            } else if (area.compareTo(BigDecimal.ZERO) <= 0 || area.compareTo(new BigDecimal("1000")) > 0) {
                errors.add(createError("房户信息", rowNumber, "面积", "范围错误", "面积必须在1-1000平方米之间"));
            }
        }
        
        return errors;
    }

    /**
     * 创建验证错误
     */
    private TemplateValidationResult.ValidationError createError(
            String sheetName, int rowNumber, String columnName, 
            String errorType, String errorMessage) {
        
        TemplateValidationResult.ValidationError error = new TemplateValidationResult.ValidationError();
        error.setSheetName(sheetName);
        error.setRowNumber(rowNumber);
        error.setColumnName(columnName);
        error.setErrorType(errorType);
        error.setErrorMessage(errorMessage);
        
        // 设置修复建议
        switch (errorType) {
            case "必填字段":
                error.setSuggestion("请填写该字段的值");
                break;
            case "格式错误":
                error.setSuggestion("请按照正确的格式填写数据");
                break;
            case "范围错误":
                error.setSuggestion("请填写在有效范围内的数值");
                break;
            case "重复错误":
                error.setSuggestion("请使用唯一的编号，避免重复");
                break;
            case "关联错误":
                error.setSuggestion("请确保关联的数据在模板中存在");
                break;
            case "一致性错误":
                error.setSuggestion("请确保数据与关联数据保持一致");
                break;
            case "计算错误":
                error.setSuggestion("请检查数据计算是否正确");
                break;
            default:
                error.setSuggestion("请检查并修正数据");
        }
        
        return error;
    }

    /**
     * 获取字符串值
     */
    private String getStringValue(Map<String, Object> data, String key) {
        Object value = data.get(key);
        return value != null ? value.toString().trim() : null;
    }

    /**
     * 获取整数值
     */
    private Integer getIntegerValue(Map<String, Object> data, String key) {
        Object value = data.get(key);
        if (value == null) {
            return null;
        }
        if (value instanceof Number) {
            return ((Number) value).intValue();
        }
        try {
            return Integer.parseInt(value.toString().trim());
        } catch (NumberFormatException e) {
            return null;
        }
    }

    /**
     * 获取BigDecimal值
     */
    private BigDecimal getBigDecimalValue(Map<String, Object> data, String key) {
        Object value = data.get(key);
        if (value == null) {
            return null;
        }
        if (value instanceof BigDecimal) {
            return (BigDecimal) value;
        }
        if (value instanceof Number) {
            return new BigDecimal(value.toString());
        }
        try {
            return new BigDecimal(value.toString().trim());
        } catch (NumberFormatException e) {
            return null;
        }
    }
}
